import random
# 导入 Tkinter 库，用于创建图形用户界面
import tkinter as tk
from tkinter import messagebox
# 导入 winsound 库，用于播放声音
import pygame
import json
import time
from PIL import Image, ImageTk

start_time = None

# 定义扫雷游戏类
class Minesweeper:
    # 初始化游戏，设置行数、列数和地雷数量
    def __init__(self, rows, cols, mines):
        self.rows = rows
        self.cols = cols
        self.mines = mines
        # 初始化游戏棋盘，0 表示无地雷，-1 表示有地雷
        self.board = [[0] * cols for _ in range(rows)]
        # 记录每个格子是否已被翻开
        self.revealed = [[False] * cols for _ in range(rows)]
        # 记录每个格子是否被标记，在 __init__ 方法中添加标记状态
        self.marked = [[False] * cols for _ in range(rows)] 
        self.game_over = False
        self.win = False
        self.start_time = None
        # 放置地雷
        self._place_mines()
        # 计算每个格子周围的地雷数量
        self._calculate_numbers()

    # 随机放置地雷
    def _place_mines(self):
        positions = random.sample(range(self.rows * self.cols), self.mines)
        for pos in positions:
            row, col = divmod(pos, self.cols)
            self.board[row][col] = -1

    # 计算每个非地雷格子周围的地雷数量
    def _calculate_numbers(self):
        directions = [(i, j) for i in [-1, 0, 1] for j in [-1, 0, 1] if (i, j) != (0, 0)]
        for r in range(self.rows):
            for c in range(self.cols):
                if self.board[r][c] == -1:
                    continue
                count = 0
                for dr, dc in directions:
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < self.rows and 0 <= nc < self.cols and self.board[nr][nc] == -1:
                        count += 1
                self.board[r][c] = count

    # 翻开指定位置的格子
    def reveal(self, row, col):
        if self.revealed[row][col] or self.game_over:
            return
        self.revealed[row][col] = True
        if self.board[row][col] == -1:
            self.game_over = True
            return
        if self.board[row][col] == 0:
            # 使用队列代替递归，避免堆栈溢出
            queue = [(row, col)]
            while queue:
                r, c = queue.pop(0)
                for dr in [-1, 0, 1]:
                    for dc in [-1, 0, 1]:
                        nr, nc = r + dr, c + dc
                        if 0 <= nr < self.rows and 0 <= nc < self.cols and not self.revealed[nr][nc]:
                            self.revealed[nr][nc] = True
                            if self.board[nr][nc] == 0:
                                queue.append((nr, nc))
        
        # 优化胜利条件检查
        unrevealed = sum(1 for row in self.revealed for cell in row if not cell)
        if unrevealed == self.mines:
            self.win = True
            self.game_over = True

    # 打印游戏棋盘，可选择是否显示地雷
    def print_board(self, show_mines=False):
        pass

    # 标记或取消标记指定位置的格子
    def mark(self, row, col):
        if not self.revealed[row][col] and not self.game_over:
            self.marked[row][col] = not self.marked[row][col]
            
    # 计算按钮大小
    def _calculate_button_size(self):
        """计算并返回合适的按钮尺寸"""
        game_frame = globals().get('game_frame')
        game_frame.config(width=700, height=700)
        cell_size = self._get_cell_size()
        return cell_size, cell_size

    def _get_cell_size(self):
        # 确保按钮宽高比例一致，呈现正方形
        cell_size = min(int(700/max(self.rows, self.cols)), 700//min(self.rows, self.cols))
        return cell_size

    def _create_button(self, row, col):
        btn_width, btn_height = self._calculate_button_size()
        """创建单个按钮"""
        btn = tk.Button(game_frame, 
                       text=' ', 
                       width=btn_width, 
                       height=btn_height, 
                       command=lambda r=row, c=col: on_click(r, c), 
                       font=('Comic Sans MS', 16, 'bold'), 
                       bg="#2196F3", 
                       fg="white", 
                       activebackground="#1976D2", 
                       relief=tk.RAISED, 
                       bd=3) 
        btn.bind("<Button-3>", lambda event, r=row, c=col: on_right_click(r, c))
        btn.grid(row=row, column=col, padx=2, pady=2, sticky='nsew')
        return btn

    def _configure_grid(self):
        """配置网格布局权重"""
        game_frame = globals().get('game_frame')
        self._set_grid_weights(game_frame)

    def _set_grid_weights(self, game_frame):
        game_frame.columnconfigure(index=0, weight=1)
        game_frame.rowconfigure(index=0, weight=1)
        for col in range(self.cols):
            game_frame.columnconfigure(col, weight=1)
        for row in range(self.rows):
            game_frame.rowconfigure(row, weight=1)
        return self._get_cell_size()

if __name__ == '__main__':
    # 循环播放背景音乐，确保异步播放不被中断
    import pygame
    import json
    import time
    pygame.mixer.init()
    pygame.mixer.music.load('sound/background.mp3')
    pygame.mixer.music.play(-1)
    # 定义不同难度的参数
    DIFFICULTY_LEVELS = {
        '简单': (8, 8, 10),
        '一般': (16, 16, 40),
        '困难': (24, 24, 99)
    }
    current_difficulty = '简单'
    rows, cols, mines = DIFFICULTY_LEVELS[current_difficulty]
    game = Minesweeper(rows, cols, mines)
    # 创建主窗口
    root = tk.Tk()
    root.title("猴赛雷(范版)")
    root.configure(bg="#2c3e50")  # 设置窗口背景为深色调
    root.geometry('700x900')  # 设置窗口最大尺寸

    # 创建顶部控制面板框架
    top_frame = tk.Frame(root, bg="#2c3e50", padx=10, pady=10, width=700, height=200)
    top_frame.pack(side=tk.TOP, fill=tk.X)
    top_frame.pack_propagate(0)
    
    # 创建按钮区域框架
    button_frame = tk.Frame(top_frame, bg="#2c3e50", padx=10, pady=10)
    button_frame.pack(side=tk.LEFT)
    
    def show_instructions():
        instruction_text = "游戏说明：\n1. 左键点击格子翻开。\n2. 右键点击格子标记地雷。\n3. 避开所有地雷并翻开其他格子获胜。\n"
        tk.messagebox.showinfo("游戏说明", instruction_text)

    # 创建游戏说明按钮
    instruction_btn = tk.Button(button_frame, text='游戏说明', command=show_instructions, font=('Comic Sans MS', 14), bg="#34495e", fg="white", activebackground="#2c3e50")
    instruction_btn.grid(row=1, column=3, padx=5, pady=5, sticky='ew')
    time_label = tk.Label(top_frame, text="时间: 00:00", bg="#1A237E", fg="#FFEB3B", font=('Arial', 20, 'bold'), padx=15, pady=5, relief=tk.GROOVE, bd=3)
    time_label.pack(side=tk.LEFT, padx=20)
    def update_timer():
        global start_time
        if start_time is not None and not game.game_over:
            elapsed_time = int(time.time() - start_time)
            minutes = elapsed_time // 60
            seconds = elapsed_time % 60
            time_label.config(text=f"时间: {minutes:02d}:{seconds:02d}")
        root.after(1000, update_timer)
    update_timer()
    def save_score(difficulty, time):
        try:
            with open('scores.json', 'r', encoding='utf-8') as f:
                scores = json.load(f)
        except FileNotFoundError:
            scores = {'简单': [], '一般': [], '困难': []}
        scores[difficulty].append(time)
        scores[difficulty].sort()
        scores[difficulty] = scores[difficulty][:10]
        with open('scores.json', 'w', encoding='utf-8') as f:
            json.dump(scores, f, indent=4)
    def show_leaderboard():
        try:
            with open('scores.json', 'r', encoding='utf-8') as f:
                scores = json.load(f)
            leaderboard_text = "排行榜:\n"
            for difficulty in ['简单', '一般', '困难']:
                leaderboard_text += f"\n{difficulty}:\n"
                for i, score in enumerate(scores[difficulty]):
                    minutes = int(score) // 60
                    seconds = int(score) % 60
                    leaderboard_text += f"{i + 1}. {minutes:02d}:{seconds:02d}\n"
            tk.messagebox.showinfo("排行榜", leaderboard_text)
        except FileNotFoundError:
            tk.messagebox.showinfo("排行榜", "暂无排行榜数据。")
    leaderboard_btn = tk.Button(button_frame, text='排行榜', command=show_leaderboard, font=('Comic Sans MS', 14), bg="#34495e", fg="white", activebackground="#2c3e50")
    leaderboard_btn.grid(row=0, column=3, padx=5, pady=5, sticky='ew')

    # 创建扫雷区域框架
    game_frame = tk.Frame(root, width=700, height=700)
    game_frame.pack(side=tk.BOTTOM, padx=10, pady=10)
    game_frame.pack_propagate(0)  # 防止框架根据内容调整大小

    # 创建难度选择按钮
    easy_btn = tk.Button(button_frame, text='简单', command=lambda: select_difficulty('简单'), font=('Comic Sans MS', 14), bg="#27ae60", fg="white", activebackground="#2ecc71")  # 调整难度选择按钮样式
    easy_btn.grid(row=0, column=0, padx=5, pady=5, sticky='ew')
    medium_btn = tk.Button(button_frame, text='一般', command=lambda: select_difficulty('一般'), font=('Comic Sans MS', 14), bg="#f39c12", fg="white", activebackground="#f1c40f")  # 调整难度选择按钮样式
    medium_btn.grid(row=0, column=1, padx=5, pady=5, sticky='w')
    hard_btn = tk.Button(button_frame, text='困难', command=lambda: select_difficulty('困难'), font=('Comic Sans MS', 14), bg="#e74c3c", fg="white", activebackground="#c0392b")  # 调整难度选择按钮样式
    hard_btn.grid(row=0, column=2, padx=5, pady=5, sticky='w')

    def restart_game():
        global start_time
        start_time = None
        global game, root
        global buttons
        rows, cols, mines = DIFFICULTY_LEVELS[current_difficulty]
        game = Minesweeper(rows, cols, mines)
        # 销毁旧的按钮
        for r in range(len(buttons)):
            for c in range(len(buttons[0])):
                if buttons[r][c] is not None:
                    buttons[r][c].destroy()
        # 重新创建按钮矩阵
        rows, cols, mines = DIFFICULTY_LEVELS[current_difficulty]
        game = Minesweeper(rows, cols, mines)
        buttons = [[None] * cols for _ in range(rows)]
        for r in range(rows):
            for c in range(cols):
                if buttons[r][c] is not None:
                    buttons[r][c].destroy()
        buttons = setup_buttons(game)

    restart_btn = tk.Button(button_frame, text='重新开始', command=restart_game, font=('Comic Sans MS', 14), bg="#9b59b6", fg="white", activebackground="#8e44ad")  # 调整重新开始按钮样式
    restart_btn.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky='ew')



    # 处理左键点击事件
    def on_click(row, col):
        global start_time
        if start_time is None:
            start_time = time.time()
        game.reveal(row, col)
        # 更新按钮显示
        update_buttons()
        if game.board[row][col] == -1:
            # 播放爆炸音效
            try:
                explosion_sound = pygame.mixer.Sound('sound/explosion.mp3')
                explosion_sound.play()
            except Exception as e:
                print(f'播放爆炸音效时出错: {e}')
        if game.game_over:
            if game.win:
                end_time = time.time()
                elapsed_time = end_time - start_time
                save_score(current_difficulty, elapsed_time)
            # 显示所有地雷
            show_all_mines()
            if game.win:
                # 播放胜利音效
                try:
                    win_sound = pygame.mixer.Sound('sound/win.mp3')
                    win_sound.play()
                except Exception as e:
                    print(f'播放胜利音效时出错: {e}')
                tk.messagebox.showinfo("游戏结束", "恭喜你，赢得了游戏！")
            else:
                tk.messagebox.showinfo("游戏失败", "哎呀！您踩到地雷了，游戏结束啦，请点击 '重新开始' 再来一局。")

    # 初始化按钮矩阵
    def setup_buttons(game):
        global btn_size, buttons
        btn_size = game._calculate_button_size()
        
        # 初始化按钮矩阵
        buttons = [[None] * game.cols for _ in range(game.rows)]
        
        # 创建所有按钮
        for row in range(game.rows):
            for col in range(game.cols):
                buttons[row][col] = game._create_button(row, col)
        
        # 配置网格布局
        game._configure_grid()
        
        return buttons

    # 处理右键点击事件
    def on_right_click(row, col):
        game.mark(row, col)
        # 更新按钮显示
        update_buttons()
        # 播放标记音效
        try:
            mark_sound = pygame.mixer.Sound('sound/mark.mp3')
            mark_sound.play()
        except Exception as e:
            print(f'播放标记音效时出错: {e}')

    # 更新按钮的显示状态
    def update_buttons():
        for r in range(game.rows):
            for c in range(game.cols):
                if game.revealed[r][c]:
                    if game.board[r][c] == -1:
                        buttons[r][c].config(text='*', bg='red')
                    else:
                        buttons[r][c].config(text=str(game.board[r][c]), state='disabled', bg='white')
                elif game.marked[r][c]:
                    if 'flag_image' not in globals():
                        global flag_image
                        img = Image.open(r'pic\flag.png')
                        img = img.resize((buttons[r][c].winfo_width(), buttons[r][c].winfo_height()))
                        flag_image = ImageTk.PhotoImage(img)
                    buttons[r][c].config(image=flag_image, text='', compound=tk.CENTER)
                else:
                    buttons[r][c].config(text=' ', bg='#3498db', image='')

    # 显示所有地雷
    def show_all_mines():
        for r in range(game.rows):
            for c in range(game.cols):
                if game.board[r][c] == -1:
                    buttons[r][c].config(text='*', bg='red')

    # 处理难度选择
    def select_difficulty(difficulty):
        global current_difficulty, game, buttons
        current_difficulty = difficulty
        restart_game()

    buttons = setup_buttons(game)

    # 进入主事件循环
    root.mainloop()